package com.licq.ldoc.parser.impl;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.licq.ldoc.domain.AttributeElement;
import com.licq.ldoc.domain.Element;
import com.licq.ldoc.domain.ElementType;
import com.licq.ldoc.domain.Occurrencies;
import com.licq.ldoc.support.bean.KeyValue;
import com.licq.ldoc.utils.ClassUtils;

/**
 * 
 * @author liujian
 *
 */
public final class AttributeElementParser extends AbstractElementParser<AttributeElement> {
	private static transient Log logger = LogFactory.getLog(AttributeElementParser.class);
	
	private Field field;
	
	private AttributeElementParser(Field field) {
		this.field = field;
	}
	
	public static AttributeElement parse(Field field) {
		return new AttributeElementParser(field).doParse();
	}

	@Override
	public AttributeElement doParse() {
		if (ClassUtils.isMapper(field.getType()) 
    			&& !ClassUtils.isBasicJavaTypeMapper(field)) {
    		//log it for aware
    		if (logger.isInfoEnabled()) {
    			logger.info("has an unbasic type mapper type, field = " + field);
    		}
    		return parseClassWithMapper();
    	} else {
    		return parseClassOrWithWrapper();
    	}
	}
	
	private AttributeElement parseClassWithMapper() {
    	KeyValue<Class<?>, Class<?>> nestedClassPair = ClassUtils.getMapperNestedType(field);
    	forwardCurrentLevel();
    	AttributeElement attributeElement = new AttributeElement(getCurrentLevel(), field.getName(), 
    			ElementType.map(nestedClassPair.getKey(), nestedClassPair.getValue()), 
    			Occurrencies.ANY
    	);
    	parseAnnotations(attributeElement);
    	backwardCurrentLevel();
    	return attributeElement;
	}

	/**
     * 处理用户类或用户类的Collection, Array
     * @param field
     * @param element
     */
	private AttributeElement parseClassOrWithWrapper() {
		Class<?> actualClazz = null;
		ElementType type;
		Occurrencies defaultOccurs = null;
		if (ClassUtils.isWrapper(field.getType())) {
			actualClazz = ClassUtils.getWrapperNestedType(field);
			type = field.getType().isArray()
					? ElementType.array(actualClazz)
					: ElementType.collection(actualClazz);
			defaultOccurs = Occurrencies.ANY;
		} else {
			actualClazz = field.getType();
			type = ElementType.type(actualClazz);
			defaultOccurs = Occurrencies.ZERO_OR_ONCE;
		}
		forwardCurrentLevel();
		AttributeElement attributeElement = new AttributeElement(getCurrentLevel(), field.getName(),
				type, defaultOccurs);
		parseAnnotations(attributeElement);
		//若该类被标记为显示忽略，就没有必要继续解析
		if (!attributeElement.isIgnored()) {
			if (!isClazzHandled(actualClazz)) {
				recordClazzToHandled(actualClazz, attributeElement);
				parseFields(actualClazz, attributeElement);
			} else {
				linkToExistsElement(attributeElement, getExistsElement(actualClazz));
			}
		}
		backwardCurrentLevel();
		return attributeElement;
	}

    private void linkToExistsElement(Element element, Element existsElement) {
    	element.setLink(getAnchor(existsElement));
	}

	private String getAnchor(Element handledElement) {
		if (!handledElement.hasAnchor()) {
			handledElement.makeAnchor();
		}
		return handledElement.getAnchor();
	}

	private void parseAnnotations(AttributeElement element) {
		Annotation[] annotations = field.getAnnotations();
		AnnotationParsees.parse(element, annotations);
	}

}
